﻿//----------------------------------------------------------------
// Desc: 数字对象模型及简单功能函数
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2011-05-05
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#pragma pack(push, 1)


//----------------------------------------------------------------
//
//----------------------------------------------------------------
struct FFLOAT16
{
    FDECLARE_STRUCT(FFLOAT16)

    FINLINE FFLOAT16() { vl = 0; };
    FINLINE FFLOAT16( float );
    FINLINE FFLOAT16( const FFLOAT16& );

    FINLINE operator float ();

    FINLINE bool operator == ( const FFLOAT16& ) const;
    FINLINE bool operator != ( const FFLOAT16& ) const;

    unsigned short vl;
};


//----------------------------------------------------------------
//
//----------------------------------------------------------------
struct FVECTOR2
{
    FDECLARE_STRUCT(FVECTOR2)

    FINLINE FVECTOR2() { x = y = 0; };
    FINLINE FVECTOR2( const float * );
    FINLINE FVECTOR2( float x, float y );

    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FVECTOR2& operator += ( const FVECTOR2& );
    FINLINE FVECTOR2& operator -= ( const FVECTOR2& );
    FINLINE FVECTOR2& operator *= ( float );
    FINLINE FVECTOR2& operator /= ( float );
    FINLINE FVECTOR2 operator + () const;
    FINLINE FVECTOR2 operator - () const;
    FINLINE FVECTOR2 operator + ( const FVECTOR2& ) const;
    FINLINE FVECTOR2 operator - ( const FVECTOR2& ) const;
    FINLINE FVECTOR2 operator * ( float ) const;
    FINLINE FVECTOR2 operator / ( float ) const;

    friend FINLINE FVECTOR2 operator * ( float, const FVECTOR2& );
    friend FINLINE float operator^ (const FVECTOR2 &v, const FVECTOR2 &u);
    friend FINLINE float operator% (const FVECTOR2 &v, const FVECTOR2 &u);

    FINLINE bool operator == ( const FVECTOR2& ) const;
    FINLINE bool operator != ( const FVECTOR2& ) const;

    // 设置数据
    FINLINE void Set(float nx, float ny);
    // 与坐标v形成的弧度
    FINLINE float Angle(const FVECTOR2 *v = 0) const;
    // 夹住
    FINLINE void Clamp(const float max);
    // 归一化
    FINLINE FVECTOR2* Normalize();
    // 旋转一定弧度
    FINLINE FVECTOR2* Rotate(float a);
    // 向量长度
    FINLINE float Length();
    // 向量长度平方
    FINLINE float LengthSq();

    float x, y;
};


//----------------------------------------------------------------
//
//----------------------------------------------------------------
struct FVECTOR3
{
    FDECLARE_STRUCT(FVECTOR3)

    FINLINE FVECTOR3() { x = y = z = 0; };
    FINLINE FVECTOR3( const float * );
    FINLINE FVECTOR3( const FVECTOR3& );
    FINLINE FVECTOR3( float x, float y, float z );

    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FVECTOR3& operator += ( const FVECTOR3& );
    FINLINE FVECTOR3& operator -= ( const FVECTOR3& );
    FINLINE FVECTOR3& operator += ( float );
    FINLINE FVECTOR3& operator -= ( float );
    FINLINE FVECTOR3& operator *= ( float );
    FINLINE FVECTOR3& operator /= ( float );

    FINLINE FVECTOR3 operator + () const;
    FINLINE FVECTOR3 operator - () const;

    FINLINE FVECTOR3 operator + ( const FVECTOR3& ) const;
    FINLINE FVECTOR3 operator - ( const FVECTOR3& ) const;
    FINLINE FVECTOR3 operator * ( float ) const;
    FINLINE FVECTOR3 operator / ( float ) const;

    friend FINLINE FVECTOR3 operator * ( float, const struct FVECTOR3& );

    FINLINE bool operator == ( const FVECTOR3& ) const;
    FINLINE bool operator != ( const FVECTOR3& ) const;

    FINLINE void Set(float x, float y, float z);
    FINLINE void Set(DWORD vl);
    FINLINE float Length() const;
    FINLINE float LengthSq() const;
    FINLINE FVECTOR3* Normalize();

    float x;
    float y;
    float z;
};


//----------------------------------------------------------------
//
//----------------------------------------------------------------
struct FVECTOR4
{
    FDECLARE_STRUCT(FVECTOR4)

    FINLINE FVECTOR4() { x = y = z = w = 0; };
    FINLINE FVECTOR4( const float* );
    FINLINE FVECTOR4( const FVECTOR3& xyz, float w );
    FINLINE FVECTOR4( float x, float y, float z, float w );

    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FVECTOR4& operator += ( const FVECTOR4& );
    FINLINE FVECTOR4& operator -= ( const FVECTOR4& );
    FINLINE FVECTOR4& operator *= ( float );
    FINLINE FVECTOR4& operator /= ( float );

    FINLINE FVECTOR4 operator + () const;
    FINLINE FVECTOR4 operator - () const;

    FINLINE FVECTOR4 operator + ( const FVECTOR4& ) const;
    FINLINE FVECTOR4 operator - ( const FVECTOR4& ) const;
    FINLINE FVECTOR4 operator * ( float ) const;
    FINLINE FVECTOR4 operator / ( float ) const;

    friend FINLINE FVECTOR4 operator * ( float, const FVECTOR4& );

    FINLINE bool operator == ( const FVECTOR4& ) const;
    FINLINE bool operator != ( const FVECTOR4& ) const;

    FINLINE void Set(float x, float y, float z, float w);
    FINLINE void Set(const FVECTOR3& xyz, float w);

    float x, y, z, w;
};


//----------------------------------------------------------------
// 4x4矩阵
//----------------------------------------------------------------
struct FQUATERNION;
struct FMATRIX
{
    FDECLARE_STRUCT(FMATRIX)

    FINLINE FMATRIX();
    FINLINE FMATRIX( const float * );
    FINLINE FMATRIX( const FMATRIX& );
    FINLINE FMATRIX( float _11, float _12, float _13, float _14,
                     float _21, float _22, float _23, float _24,
                     float _31, float _32, float _33, float _34,
                     float _41, float _42, float _43, float _44 );
    FINLINE FMATRIX( FQUATERNION* qt );

    FINLINE float& operator () ( UINT Row, UINT Col );
    FINLINE float  operator () ( UINT Row, UINT Col ) const;

    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FMATRIX& operator *= ( const FMATRIX& );
    FINLINE FMATRIX& operator += ( const FMATRIX& );
    FINLINE FMATRIX& operator -= ( const FMATRIX& );
    FINLINE FMATRIX& operator *= ( float );
    FINLINE FMATRIX& operator /= ( float );

    FINLINE FMATRIX operator + () const;
    FINLINE FMATRIX operator - () const;

    FINLINE FMATRIX operator * ( const FMATRIX& ) const;
    FINLINE FMATRIX operator + ( const FMATRIX& ) const;
    FINLINE FMATRIX operator - ( const FMATRIX& ) const;
    FINLINE FMATRIX operator * ( float ) const;
    FINLINE FMATRIX operator / ( float ) const;

    friend FINLINE FMATRIX operator * ( float, const FMATRIX& );

    FINLINE bool operator == ( const FMATRIX& ) const;
    FINLINE bool operator != ( const FMATRIX& ) const;

    FINLINE FVECTOR3& GetV3(size_t row);
    FINLINE FVECTOR4& GetV4(size_t row);
    FINLINE bool IsParity();
    FINLINE FQUATERNION* GetRotate(FQUATERNION* out);
    FINLINE FVECTOR3* GetScale(FVECTOR3* pOut);
    FINLINE FVECTOR3& GetTranslation();
    FINLINE void RemoveRotate();
    FINLINE void RemoveScale();
    FINLINE void RemoveTranslation();

    union
    {
        struct
        {
            float _11, _12, _13, _14;
            float _21, _22, _23, _24;
            float _31, _32, _33, _34;
            float _41, _42, _43, _44;
        };
        float m[4][4];
    };
};


//----------------------------------------------------------------
// 四元素
//----------------------------------------------------------------
struct FQUATERNION
{
    FDECLARE_STRUCT(FQUATERNION)

    FINLINE FQUATERNION() { Identity();};
    FINLINE FQUATERNION( const float * );
    FINLINE FQUATERNION( float x, float y, float z, float w );
    FINLINE FQUATERNION( FVECTOR3* v, float w );
    FINLINE FQUATERNION( FMATRIX* mat );

    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FQUATERNION& operator += ( const FQUATERNION& );
    FINLINE FQUATERNION& operator -= ( const FQUATERNION& );
    FINLINE FQUATERNION& operator *= ( const FQUATERNION& );
    FINLINE FQUATERNION& operator *= ( float );
    FINLINE FQUATERNION& operator /= ( float );

    FINLINE FQUATERNION  operator + () const;
    FINLINE FQUATERNION  operator - () const;

    FINLINE FQUATERNION operator + ( const FQUATERNION& ) const;
    FINLINE FQUATERNION operator - ( const FQUATERNION& ) const;
    FINLINE FQUATERNION operator * ( const FQUATERNION& ) const;
    FINLINE FQUATERNION operator * ( float ) const;
    FINLINE FQUATERNION operator / ( float ) const;

    friend FINLINE FQUATERNION operator * (float, const FQUATERNION& );

    FINLINE bool operator == ( const FQUATERNION& ) const;
    FINLINE bool operator != ( const FQUATERNION& ) const;

    // 获取虚部
    FINLINE FVECTOR3* GetVirtual(FVECTOR3* out);
    // 正规化四元素
    FINLINE void Identity();
    // 取偏航相关数据
    FINLINE float Yaw();
    FINLINE float Pitch();
    FINLINE float Roll();

    float x, y, z, w;
};


//----------------------------------------------------------------
//
//----------------------------------------------------------------
struct FCOLOR
{
    FDECLARE_STRUCT(FCOLOR)

    FINLINE FCOLOR() { r = g = b = a = 1; };
    FINLINE FCOLOR( DWORD  argb );
    FINLINE FCOLOR( const float * );
    FINLINE FCOLOR( float r, float g, float b, float a );

    FINLINE operator DWORD () const;
    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FCOLOR& operator += ( const FCOLOR& );
    FINLINE FCOLOR& operator -= ( const FCOLOR& );
    FINLINE FCOLOR& operator *= ( float );
    FINLINE FCOLOR& operator /= ( float );

    FINLINE FCOLOR operator + () const;
    FINLINE FCOLOR operator - () const;

    FINLINE FCOLOR operator + ( const FCOLOR& ) const;
    FINLINE FCOLOR operator - ( const FCOLOR& ) const;
    FINLINE FCOLOR operator * ( float ) const;
    FINLINE FCOLOR operator / ( float ) const;

    friend FINLINE FCOLOR operator * ( float, const FCOLOR& );

    FINLINE bool operator == ( const FCOLOR& ) const;
    FINLINE bool operator != ( const FCOLOR& ) const;

    // 夹住颜色到颜色空间范围
    FINLINE void Clamp();
    // 设置硬件颜色
    FINLINE void SetHWColor(DWORD col);
    // 获取硬件颜色
    FINLINE DWORD GetHWColor() const;
    // 设置分量
    FINLINE void Set(float r, float g, float b, float a = 1.0f);
    // 设置并转换数据结构
    FINLINE FCOLOR* Set(FVECTOR3* in);
    FINLINE FCOLOR* Set(FVECTOR4* in, bool with_alpha);
    // 获取并转换数据结构
    FINLINE void Get(FVECTOR3* out);
    FINLINE void Get(FVECTOR4* out, bool with_alpha);

    float r, g, b, a;
};


//----------------------------------------------------------------
// 对象类型
//----------------------------------------------------------------
struct FRAY;
struct FAABB;
struct FAABB_CENTER;
struct FPLANE;
struct FFRUSTUM;


//----------------------------------------------------------------
// 三角形
//----------------------------------------------------------------
struct FTRIANGLE
{
    FDECLARE_STRUCT(FTRIANGLE)

    // 碰撞测试
    FINLINE FTRIANGLE(){}
    FINLINE FTRIANGLE(FVECTOR3* p0, FVECTOR3* p1, FVECTOR3* p2);
    FINLINE bool HitRay(FRAY* ray, FVECTOR3* hit_postion = 0);
    FINLINE FVECTOR3* GetNormal(FVECTOR3* out);
    FINLINE bool IsSameSide(const FVECTOR3& p1, const FVECTOR3& p2, const FVECTOR3& a, const FVECTOR3& b);
    FINLINE bool IsPointInside(const FVECTOR3& p);

    FINLINE void operator = (const FTRIANGLE& b);

    FVECTOR3 v0, v1, v2;
};


//----------------------------------------------------------------
// 三角形（带法线）
//----------------------------------------------------------------
struct FTRIANGLE_NORMAL : public FTRIANGLE
{
    FDECLARE_STRUCT(FTRIANGLE_NORMAL)

    FVECTOR3 normal;
};


//----------------------------------------------------------------
// 球
//----------------------------------------------------------------
struct FSPHERE
{
    FDECLARE_STRUCT(FSPHERE)

    // 碰撞测试
    FINLINE FSPHERE(){ radius = 1.0f;}
    FINLINE FSPHERE(FVECTOR3* c, float r);
    FINLINE bool HitAABB(FAABB* aabb);
    FINLINE bool HitFrustum(FFRUSTUM* f);

    FINLINE void operator = (const FSPHERE& b);

    FVECTOR3 center;
    float radius;
};


//----------------------------------------------------------------
// 射线
//----------------------------------------------------------------
struct FRAY
{
    FDECLARE_STRUCT(FRAY)

    FINLINE FRAY(){}
    FINLINE FRAY(FVECTOR3* p, FVECTOR3* d);
    // 根据一个长度，得到射线的另一个端点
    FINLINE FVECTOR3* DstPoint(float distance, FVECTOR3* dst, bool flip = false);
    // 碰撞测试
    FINLINE bool HitAABB(FAABB* aabb);
    FINLINE bool HitFrustum(FFRUSTUM* f, FVECTOR3* hit_position = 0);
    FINLINE bool HitPlane(FPLANE* plane, FVECTOR3* hit_position = 0);

    FINLINE void operator = (const FRAY& b);

    FVECTOR3 origin;
    FVECTOR3 dir;
};


//----------------------------------------------------------------
// 轴对称包转盒
//----------------------------------------------------------------
struct FAABB
{
    FDECLARE_STRUCT(FAABB)

    FINLINE FAABB(){ Clear(); }
    FINLINE FAABB(FVECTOR3* vmin, FVECTOR3* vmax);
    FINLINE FAABB(const FAABB& b);
    // 包围盒是否有效或者说是否为空
    FINLINE bool Empty() const;
    // 清空包围盒
    FINLINE void Clear();
    // 转换为8个顶点并输出
    FINLINE void ToPoint(FVECTOR3* vtx);
    // 放置顶点，设置盒子
    FINLINE FAABB& Push(FVECTOR3* v);
    // 放置一个盒子合并
    FINLINE void Merge(FAABB* b);
    // 设置值
    FINLINE FAABB& Set(FVECTOR3* _min, FVECTOR3* _max);
    // 测试点是否在盒子内
    FINLINE bool HitPoint(FVECTOR3* pos);
    // 碰撞测试
    FINLINE bool HitSphere(FSPHERE* sphere);
    FINLINE bool HitRay(FRAY* ray);
    FINLINE bool HitAABB(FAABB* b, FAABB* intersection = 0);
    FINLINE bool HitFrustum(FFRUSTUM* f);
    FINLINE EF_INTERSECTION_TYPE HitPlane(FPLANE* plane);
    FINLINE EF_INTERSECTION_TYPE HitPlane(FVECTOR3* p, FVECTOR3* n);
    // 获取最靠近测试点的盒子顶点
    FINLINE void GetNear(FVECTOR3* p, FVECTOR3* out);
    // 扩张、收缩
    FINLINE FAABB& Inflate(float v);
    FINLINE FAABB& Inflate(FVECTOR3* i);
    FINLINE FAABB& Inflate(float x, float y, float z);
    // 获取各轴长度
    FINLINE float LengthX();
    FINLINE float LengthY();
    FINLINE float LengthZ();
    FINLINE FVECTOR3* Length(FVECTOR3* ret);

    FINLINE void operator = (const FAABB& b);

    FVECTOR3 vMin;
    FVECTOR3 vMax;
};


//----------------------------------------------------------------
// 带中心的AABB
//----------------------------------------------------------------
struct FAABB_CENTER : public FAABB
{
    FDECLARE_STRUCT(FAABB_CENTER)

    FINLINE FAABB_CENTER(){}
    FINLINE FAABB_CENTER(FAABB* aabb);
    // 创建中心坐标
    FINLINE FVECTOR3& MakeCenter();

    FVECTOR3 vCenter;
};


//----------------------------------------------------------------
// 平面
//----------------------------------------------------------------
struct FPLANE
{
    FDECLARE_STRUCT(FPLANE)

    FINLINE FPLANE() { a = b = c = d = 0; };
    FINLINE FPLANE( const float* );
    FINLINE FPLANE( float a, float b, float c, float d );

    FINLINE operator float* ();
    FINLINE operator const float* () const;

    FINLINE FPLANE& operator *= ( float );
    FINLINE FPLANE& operator /= ( float );

    FINLINE FPLANE operator + () const;
    FINLINE FPLANE operator - () const;

    FINLINE FPLANE operator * ( float ) const;
    FINLINE FPLANE operator / ( float ) const;

    friend FINLINE FPLANE operator * ( float, const FPLANE& );

    FINLINE bool operator == ( const FPLANE& ) const;
    FINLINE bool operator != ( const FPLANE& ) const;

    FINLINE FVECTOR3& GetNormal();
    FINLINE float GetDistance();

    float a, b, c, d;
};


//----------------------------------------------------------------
// 视锥
// 8个点的摆放位置
//   6-------7
//   |\     /|
//   | 2---3 |
//   | |   | |
//   | 0---1 |
//   |/     \|
//   4-------5
// 0/1/2/3 是近平面
// 4/5/6/7 是远平面
// 0/1/2/3 四个顶点组成近平面
// 0/2/6/4 四个顶点组成左平面
// 2/3/7/6 四个顶点组成上平面
//----------------------------------------------------------------
struct FFRUSTUM
{
    FDECLARE_STRUCT(FFRUSTUM)

    FINLINE FFRUSTUM(){}
    FINLINE FFRUSTUM(FMATRIX* view, FMATRIX* proj, float distance = 0);
    // 构建视锥（可设置远平面距离）
    // .distance 如果大于0则设置视锥远平面到近平面的距离为distance，小于或等于0，按proj原始距离设置
    FINLINE void Make(FMATRIX* view, FMATRIX* proj, float distance = 0);
    // 通过视锥的8个顶点生成视锥（8个顶点的排列如上下文所示）
    FINLINE void Make(FVECTOR3* vp);
    // 测试点中否在视锥内
    FINLINE bool HitPoint(FVECTOR3* p);
    // 碰撞测试
    FINLINE bool HitShpere(FSPHERE* sphere);
    FINLINE bool HitRay(FRAY* ray, FVECTOR3* hit_position = 0);
    FINLINE bool HitAABB(FAABB* aabb);
    FINLINE EF_INTERSECTION_TYPE HitPlane(FPLANE* plane);
    FINLINE EF_INTERSECTION_TYPE HitPlane(FVECTOR3* p, FVECTOR3* n);

    FINLINE void operator = (const FFRUSTUM& b);

    FPLANE plane[ePFT_MAX];
    FVECTOR3 position[8];
};


//----------------------------------------------------------------
// 碰撞测试结果
//----------------------------------------------------------------
struct FHITRESULT
{
    FDECLARE_STRUCT(FHITRESULT)

    FINLINE FHITRESULT()
        :distance(0)
        ,data1(0)
        ,data2(0)
    {}
    FINLINE bool operator > (const FHITRESULT& r) const
    {
        return distance > r.distance;
    }
    FINLINE bool operator < (const FHITRESULT& r) const
    {
        return distance < r.distance;
    }

    float distance;             // 碰撞距离（必然返回）
    FVECTOR3 position, normal;  // 碰撞点、该点法线（可选返回）
    FTRIANGLE tri;              // 三角形（可选返回）
    DWORD data1,data2;          // 扩展数据（具体由功能模块定义）
};


//----------------------------------------------------------------
// 位操作
// mem_count指明内存字节数量，一个字节代表8个位，如 FBIT_OPERATION<3>就可以支持24个位
//----------------------------------------------------------------
template < size_t mem_count >
struct FBIT_OPERATION
{
    FDECLARE_STRUCT(FBIT_OPERATION)

    FINLINE FBIT_OPERATION();
    // 将所有位置设为1或者0
    FINLINE void set_all(bool one);
    // 设置指定位为1或者0
    FINLINE void set(size_t bit_position, bool one);
    // 获取指位的状态是不是1
    FINLINE bool get(size_t bit_position);

    FINLINE bool operator [] (size_t bit_position);
    FINLINE bool operator == (const FBIT_OPERATION<mem_count>& b) const;

    BYTE data[mem_count];
};


#pragma pack(pop)


//----------------------------------------------------------------
//
//----------------------------------------------------------------
// 32位符点数转16位符点数
extern FAPI FFLOAT16* FFloat32To16Array( FFLOAT16 *pOut, const float *pIn, UINT n );
// 16位符点数转32位符点数
extern FAPI float* FFloat16To32Array( float *pOut, const FFLOAT16 *pIn, UINT n );


//----------------------------------------------------------------
//
//----------------------------------------------------------------
FINLINE float FVec2Length( const FVECTOR2 *pV );
FINLINE float FVec2LengthSq( const FVECTOR2 *pV );
FINLINE float FVec2Dot( const FVECTOR2 *pV1, const FVECTOR2 *pV2 );
// Z component of ((x1,y1,0) cross (x2,y2,0))
FINLINE float FVec2CCW( const FVECTOR2 *pV1, const FVECTOR2 *pV2 );
FINLINE FVECTOR2* FVec2Add( FVECTOR2 *pOut, const FVECTOR2 *pV1, const FVECTOR2 *pV2 );
FINLINE FVECTOR2* FVec2Subtract( FVECTOR2 *pOut, const FVECTOR2 *pV1, const FVECTOR2 *pV2 );
// Minimize each component.  x = min(x1, x2), y = min(y1, y2)
FINLINE FVECTOR2* FVec2Minimize( FVECTOR2 *pOut, const FVECTOR2 *pV1, const FVECTOR2 *pV2 );
// Maximize each component.  x = max(x1, x2), y = max(y1, y2)
FINLINE FVECTOR2* FVec2Maximize( FVECTOR2 *pOut, const FVECTOR2 *pV1, const FVECTOR2 *pV2 );
FINLINE FVECTOR2* FVec2Scale( FVECTOR2 *pOut, const FVECTOR2 *pV, float s );
// Linear interpolation. V1 + s(V2-V1)
FINLINE FVECTOR2* FVec2Lerp( FVECTOR2 *pOut, const FVECTOR2 *pV1, const FVECTOR2 *pV2, float s );
FINLINE FVECTOR2* FVec2Normalize( FVECTOR2 *pOut, const FVECTOR2 *pV );
// 计算角度
FINLINE bool FVec2Angle( FVECTOR2 *pA, const FVECTOR2 *pB, float& angle );
// 旋转
FINLINE FVECTOR2* FVec2Rotate( FVECTOR2 *pA, float a );


//----------------------------------------------------------------
//
//----------------------------------------------------------------
FINLINE float FVec3Length( const FVECTOR3 *pV );
FINLINE float FVec3LengthSq( const FVECTOR3 *pV );
// 点乘（求两法线的夹角）
FINLINE float FVec3Dot( const FVECTOR3 *pV1, const FVECTOR3 *pV2 );
// 叉乘（求两法线的组成平面的垂线）
FINLINE FVECTOR3* FVec3Cross( FVECTOR3 *pOut, const FVECTOR3 *pV1, const FVECTOR3 *pV2 );
FINLINE FVECTOR3* FVec3Add( FVECTOR3 *pOut, const FVECTOR3 *pV1, const FVECTOR3 *pV2 );
FINLINE FVECTOR3* FVec3Subtract( FVECTOR3 *pOut, const FVECTOR3 *pV1, const FVECTOR3 *pV2 );
// Minimize each component.  x = min(x1, x2), y = min(y1, y2), ...
FINLINE FVECTOR3* FVec3Minimize( FVECTOR3 *pOut, const FVECTOR3 *pV1, const FVECTOR3 *pV2 );
// Maximize each component.  x = max(x1, x2), y = max(y1, y2), ...
FINLINE FVECTOR3* FVec3Maximize( FVECTOR3 *pOut, const FVECTOR3 *pV1, const FVECTOR3 *pV2 );
FINLINE FVECTOR3* FVec3Scale( FVECTOR3 *pOut, const FVECTOR3 *pV, float s);
// 两向量的线性插值
FINLINE FVECTOR3* FVec3Lerp( FVECTOR3 *pOut, const FVECTOR3 *pV1, const FVECTOR3 *pV2, float s );
// 两个单位法线进行球面插值
extern FAPI FVECTOR3* FVec3SphericalLerp(FVECTOR3* pOut, FVECTOR3* pN1, FVECTOR3* pN2, float t);
FINLINE FVECTOR3* FVec3Normalize( FVECTOR3 *pOut, const FVECTOR3 *pV );
// Transform (x, y, z, 1) by matrix.
extern FAPI FVECTOR4* FVec3Transform( FVECTOR4 *pOut, FVECTOR3 *pV, FMATRIX *pM );
// Transform (x, y, z, 1) by matrix, project result back into w=1.
extern FAPI FVECTOR3* FVec3TransformCoord( FVECTOR3 *pOut, FVECTOR3 *pV, FMATRIX *pM );
// Transform (x, y, z, 0) by matrix.  If you transforming a normal by a 
// non-affine matrix, the matrix you pass to this function should be the 
// transpose of the inverse of the matrix you would use to transform a coord.
extern FAPI FVECTOR3* FVec3TransformNormal( FVECTOR3 *pOut, FVECTOR3 *pV, FMATRIX *pM );
// Transform Array (x, y, z, 1) by matrix. 
extern FAPI FVECTOR4* FVec3TransformArray( FVECTOR4 *pOut, UINT OutStride, FVECTOR3 *pV,
                                          UINT VStride, FMATRIX *pM, UINT n );
// Transform Array (x, y, z, 1) by matrix, project result back into w=1.
extern FAPI FVECTOR3* FVec3TransformCoordArray( FVECTOR3 *pOut, UINT OutStride, FVECTOR3 *pV,
                                               UINT VStride, FMATRIX *pM, UINT n );
// Transform (x, y, z, 0) by matrix.  If you transforming a normal by a 
// non-affine matrix, the matrix you pass to this function should be the 
// transpose of the inverse of the matrix you would use to transform a coord.
extern FAPI FVECTOR3* FVec3TransformNormalArray( FVECTOR3 *pOut, UINT OutStride, FVECTOR3 *pV,
                                                UINT VStride, FMATRIX *pM, UINT n );


//----------------------------------------------------------------
//
//----------------------------------------------------------------
FINLINE float FVec4Length( const FVECTOR4 *pV );
FINLINE float FVec4LengthSq( const FVECTOR4 *pV );
FINLINE float FVec4Dot( const FVECTOR4 *pV1, const FVECTOR4 *pV2 );
FINLINE FVECTOR4* FVec4Add( FVECTOR4 *pOut, const FVECTOR4 *pV1, const FVECTOR4 *pV2);
FINLINE FVECTOR4* FVec4Subtract( FVECTOR4 *pOut, const FVECTOR4 *pV1, const FVECTOR4 *pV2);
// Minimize each component.  x = min(x1, x2), y = min(y1, y2), ...
FINLINE FVECTOR4* FVec4Minimize( FVECTOR4 *pOut, const FVECTOR4 *pV1, const FVECTOR4 *pV2);
// Maximize each component.  x = max(x1, x2), y = max(y1, y2), ...
FINLINE FVECTOR4* FVec4Maximize( FVECTOR4 *pOut, const FVECTOR4 *pV1, const FVECTOR4 *pV2);
FINLINE FVECTOR4* FVec4Scale( FVECTOR4 *pOut, const FVECTOR4 *pV, float s);
// Linear interpolation. V1 + s(V2-V1)
FINLINE FVECTOR4* FVec4Lerp( FVECTOR4 *pOut, const FVECTOR4 *pV1, const FVECTOR4 *pV2, float s );
//
extern FAPI FVECTOR4* FVec4Transform( FVECTOR4 *pOut, FVECTOR4 *pV, FMATRIX *pM );


//----------------------------------------------------------------
//
//----------------------------------------------------------------
extern FAPI FMATRIX* FMatrixIdentity( FMATRIX *pOut );
FINLINE bool FMatrixIsIdentity( const FMATRIX *pM );
// 分解矩阵
extern FAPI bool FMatrixDecompose( FVECTOR3 *pOutScale, FQUATERNION *pOutRotation,  FVECTOR3 *pOutTranslation, FMATRIX *pM );
// 转置
extern FAPI FMATRIX* FMatrixTranspose( FMATRIX *pOut, const FMATRIX *pM );
// Matrix multiplication.  The result represents the transformation M2
// followed by the transformation M1.  (Out = M1 * M2)
extern FAPI FMATRIX* FMatrixMultiply( FMATRIX *pOut, const FMATRIX *pM1, const FMATRIX *pM2 );
// Calculate inverse of matrix.  Inversion my fail, in which case NULL will
// be returned.  The determinant of pM is also returned it pfDeterminant
// is non-NULL.
extern FAPI FMATRIX* FMatrixInverse( FMATRIX *pOut, FLOAT *pDeterminant, FMATRIX *pM );
// Build a matrix which scales by (sx, sy, sz)
extern FAPI FMATRIX* FMatrixScaling( FMATRIX *pOut, FLOAT sx, FLOAT sy, FLOAT sz );
// Build a matrix which translates by (x, y, z)
extern FAPI FMATRIX* FMatrixTranslation( FMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z );
// Build a matrix which rotates around the X axis
extern FAPI FMATRIX* FMatrixRotationX( FMATRIX *pOut, FLOAT Angle );
// Build a matrix which rotates around the Y axis
extern FAPI FMATRIX* FMatrixRotationY( FMATRIX *pOut, FLOAT Angle );
// Build a matrix which rotates around the Z axis
extern FAPI FMATRIX* FMatrixRotationZ( FMATRIX *pOut, FLOAT Angle );
// Build a matrix which rotates around an arbitrary axis
extern FAPI FMATRIX* FMatrixRotationAxis( FMATRIX *pOut, FVECTOR3 *pV, FLOAT Angle );
// Build a matrix from a quaternion
extern FAPI FMATRIX* FMatrixRotationQuaternion( FMATRIX *pOut, FQUATERNION *pQ);
// 创建平移和旋转矩阵
extern FAPI FMATRIX* FMatrixTranslationQuaternion( FMATRIX *pOut, FVECTOR3* pT, FQUATERNION* pQ );
// Yaw around the Y axis, a pitch around the X axis,
// and a roll around the Z axis.
extern FAPI FMATRIX* FMatrixRotationYawPitchRoll( FMATRIX *pOut, FLOAT Yaw, FLOAT Pitch, FLOAT Roll );
// Build a lookat matrix. (left-handed)
extern FAPI FMATRIX* FMatrixLookAtLH( FMATRIX *pOut, FVECTOR3 *pEye, FVECTOR3 *pAt, FVECTOR3 *pUp );
// Build a perspective projection matrix. (left-handed)
extern FAPI FMATRIX* FMatrixPerspectiveFovLH( FMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf );
extern FAPI FMATRIX* FMatrixReflect( FMATRIX *pOut, FPLANE *pPlane );
// build Ortho matrix, near -1.0f, far 1.0f
extern FAPI FMATRIX* FMatrixOrtho( FMATRIX* pOut, float Width, float Height );
// 构建矩阵
// .out 输出结果
// .scale 整体缩放度或者各轴缩放
// .rot 各轴旋转量
// .trans 各轴平移量
extern FAPI void FMatrixBuild(FMATRIX* out, float scale, FVECTOR3* rot, FVECTOR3* trans);
extern FAPI void FMatrixBuildSRT(FMATRIX* out, FVECTOR3* scale, FVECTOR3* rot, FVECTOR3* trans);
// 通过两个关键点混合矩阵的插值，带缩放信息
// .out 输出结果
// .s0 当前关键值各轴缩放度
// .r0 当前关键值各轴旋转量
// .t0 当前关键值各轴平移量
// .t 插值位置 [0.0f -> 1.0f]
// .s1 下一关键值各轴缩放度
// .r1 下一关键值各轴旋转量
// .t1 下一关键值各轴平移量
extern FAPI void FMatrixBlendSRT(FMATRIX* out, FVECTOR3* s0, FQUATERNION* r0, FVECTOR3* t0, float t, FVECTOR3* s1, FQUATERNION* r1, FVECTOR3* t1);
// 通过两个关键点混合矩阵的插值，不带缩放信息
// .out 输出结果
// .r0 当前关键值各轴旋转量
// .t0 当前关键值各轴平移量
// .t 插值位置 [0.0f -> 1.0f]
// .r1 下一关键值各轴旋转量
// .t1 下一关键值各轴平移量
extern FAPI void FMatrixBlendRT(FMATRIX* out, FQUATERNION* r0, FVECTOR3* t0, float t, FQUATERNION* r1, FVECTOR3* t1);


//----------------------------------------------------------------
//
//----------------------------------------------------------------
FINLINE float FQuaternionLength( const FQUATERNION *pQ );
FINLINE FQUATERNION* FQuaternionScale(FQUATERNION* pOut, const FQUATERNION* pIn, FLOAT s);
FINLINE FQUATERNION* FQuaternionAdd(FQUATERNION* pOut, const FQUATERNION* pQ1, const FQUATERNION* pQ2);
FINLINE FQUATERNION* FQuaternionNormalize(FQUATERNION* pOut, const FQUATERNION* pIn);
// Length squared, or "norm"
FINLINE float FQuaternionLengthSq( const FQUATERNION *pQ );
FINLINE float FQuaternionDot( const FQUATERNION *pQ1, const FQUATERNION *pQ2 );
// (0, 0, 0, 1)
FINLINE FQUATERNION* FQuaternionIdentity( FQUATERNION *pOut );
FINLINE bool FQuaternionIsIdentity( const FQUATERNION *pQ );
// (-x, -y, -z, w)
FINLINE FQUATERNION* FQuaternionConjugate( FQUATERNION *pOut, const FQUATERNION *pQ );
// Quaternion multiplication.  The result represents the rotation Q2
// followed by the rotation Q1.  (Out = Q2 * Q1)
FINLINE FQUATERNION* FQuaternionMultiply( FQUATERNION *pOut, const FQUATERNION *pQ1, const FQUATERNION *pQ2 );
// Compute a quaternin's axis and angle of rotation. Expects unit quaternions.
extern FAPI void FQuaternionToAxisAngle( FQUATERNION *pQ, FVECTOR3 *pAxis, FLOAT *pAngle );
// Build a quaternion from a rotation matrix.
extern FAPI FQUATERNION* FQuaternionRotationMatrix( FQUATERNION *pOut, FMATRIX *pM);
// Rotation about arbitrary axis.
extern FAPI FQUATERNION* FQuaternionRotationAxis( FQUATERNION *pOut, FVECTOR3 *pV, FLOAT Angle );
// Yaw around the Y axis, a pitch around the X axis,
// and a roll around the Z axis.
extern FAPI FQUATERNION* FQuaternionRotationYawPitchRoll( FQUATERNION *pOut, FLOAT Yaw, FLOAT Pitch, FLOAT Roll );
// Spherical linear interpolation between Q1 (t == 0) and Q2 (t == 1).
// Expects unit quaternions.
extern FAPI FQUATERNION* FQuaternionSlerp( FQUATERNION *pOut, FQUATERNION *pQ1, FQUATERNION *pQ2, FLOAT t );


//----------------------------------------------------------------
//
//----------------------------------------------------------------
// ax + by + cz + dw
FINLINE float FPlaneDot( const FPLANE *pP, const FVECTOR4 *pV);
// ax + by + cz + d
FINLINE float FPlaneDotCoord( const FPLANE *pP, const FVECTOR3 *pV);
// ax + by + cz
FINLINE float FPlaneDotNormal( const FPLANE *pP, const FVECTOR3 *pV);
FINLINE FPLANE* FPlaneScale(FPLANE *pOut, const FPLANE *pP, float s);
// Normalize plane (so that |a,b,c| == 1)
extern FAPI FPLANE* FPlaneNormalize( FPLANE *pOut, FPLANE *pP);
// Find the intersection between a plane and a line.  If the line is
// parallel to the plane, NULL is returned.
extern FAPI FVECTOR3* FPlaneIntersectLine( FVECTOR3 *pOut, FPLANE *pP, FVECTOR3 *pV1, FVECTOR3 *pV2);
// 平面与平面碰撞
// .pLineOrigin,pLineDir 输出碰撞射线
extern FAPI bool FPlaneIntersectPlane( FPLANE *pPA, FPLANE *pPB, FVECTOR3 *pLineOrigin, FVECTOR3 *pLineDir);
// Construct a plane from a point and a normal
extern FAPI FPLANE* FPlaneFromPointNormal( FPLANE *pOut, FVECTOR3 *pPoint, FVECTOR3 *pNormal);
// Construct a plane from 3 points
extern FAPI FPLANE* FPlaneFromPoints( FPLANE *pOut, FVECTOR3 *pV1, FVECTOR3 *pV2, FVECTOR3 *pV3);
// Transform a plane by a matrix.  The vector (a,b,c) must be normal.
// M should be the inverse transpose of the transformation desired.
extern FAPI FPLANE* FPlaneTransform( FPLANE *pOut, FPLANE *pP, FMATRIX *pM );
// Transform an array of planes by a matrix.  The vectors (a,b,c) must be normal.
// M should be the inverse transpose of the transformation desired.
extern FAPI FPLANE* FPlaneTransformArray( FPLANE *pOut, UINT OutStride, FPLANE *pP,
                                         UINT PStride, FMATRIX *pM, UINT n );


//----------------------------------------------------------------
//
//----------------------------------------------------------------
// 通过摄像机能数构建视锥
extern FAPI void FFrustumBuild(FFRUSTUM* frustum, FMATRIX* view, FMATRIX* proj, float distance = 0);
// 通过已知的8个顶点构建视锥（8个点的摆放位置见FFRUSTUM说明）
extern FAPI void FFrustumBuild_vp(FFRUSTUM* frustum, FVECTOR3* vp);


//----------------------------------------------------------------
//
//----------------------------------------------------------------
// (1-r, 1-g, 1-b, a)
FINLINE FCOLOR* FColorNegative(FCOLOR *pOut, const FCOLOR *pC);
FINLINE FCOLOR* FColorAdd(FCOLOR *pOut, const FCOLOR *pC1, const FCOLOR *pC2);
FINLINE FCOLOR* FColorSubtract(FCOLOR *pOut, const FCOLOR *pC1, const FCOLOR *pC2);
FINLINE FCOLOR* FColorScale(FCOLOR *pOut, const FCOLOR *pC, float s);
// (r1*r2, g1*g2, b1*b2, a1*a2)
FINLINE FCOLOR* FColorModulate(FCOLOR *pOut, const FCOLOR *pC1, const FCOLOR *pC2);
// Linear interpolation of r,g,b, and a. C1 + s(C2-C1)
FINLINE FCOLOR* FColorLerp(FCOLOR *pOut, const FCOLOR *pC1, const FCOLOR *pC2, float s);


//----------------------------------------------------------------
//
//----------------------------------------------------------------
// 计算三角形与射线碰撞数据
extern FAPI bool FIntersectTri( FVECTOR3 *p0,           // Triangle vertex 0 position
                                FVECTOR3 *p1,           // Triangle vertex 1 position
                                FVECTOR3 *p2,           // Triangle vertex 2 position
                                FVECTOR3 *pRayPos,      // Ray origin
                                FVECTOR3 *pRayDir,      // Ray direction
                                float *pDist);          // Ray-Intersection Parameter Distance
// 测试三角形与射线碰撞
extern FAPI bool FHitTriangle(FVECTOR3& p0, FVECTOR3& p1, FVECTOR3& p2, FRAY& ray, FHITRESULT& hit, EF_HIT_TYPE thr = eHT_Default, FVECTOR3* n = 0);
// 测试三角形对象与射线碰撞
extern FAPI bool FHitTriangle_tri(FTRIANGLE* tri, FRAY& ray, FHITRESULT& hit, EF_HIT_TYPE thr = eHT_Default, FVECTOR3* n = 0);
// 测试带预计算法线的三角形对象与射线碰撞
extern FAPI bool FHitTriangle_tri_normal(FTRIANGLE_NORMAL* tri_nor, FRAY& ray, FHITRESULT& hit, EF_HIT_TYPE thr = eHT_Default);
// 测试AABB与点的碰撞（点是否在AABB内）
extern FAPI bool FHitAABB_dot(FAABB* aabb, FVECTOR3* p);
// 测试AABB与球碰撞
extern FAPI bool FHitAABB_sphere(FAABB* aabb, FSPHERE* sphere);
// 测试AABB与射线碰撞
extern FAPI bool FHitAABB_ray(FAABB* aabb, FRAY* ray);
// 测试AABB与AABB碰撞
// .intersection 如果有碰撞，且不为0则返回两AABB的交集
extern FAPI bool FHitAABB_aabb(FAABB* a, FAABB* b, FAABB* intersection = 0);
// 测试AABB与平面的碰撞
// .p 平面上一点
// .n 平面法线
extern FAPI EF_INTERSECTION_TYPE FHitAABB_plane(FAABB* aabb, FPLANE* plane);
extern FAPI EF_INTERSECTION_TYPE FHitAABB_plane2(FAABB* aabb, FVECTOR3* p, FVECTOR3* n);
// 测试视锥与点的碰撞（点是否在视锥体内）
extern FAPI bool FHitFrustum_dot(FFRUSTUM* f, FVECTOR3* p);
// 测试视锥与球的碰撞
extern FAPI bool FHitFrustum_sphere(FFRUSTUM* f, FSPHERE* s);
// 测试视锥与射线碰撞
// .hit_position 返回碰撞点，如果为0不返回碰撞点
extern FAPI bool FHitFrustum_ray(FFRUSTUM* f, FRAY* ray, FVECTOR3* hit_position = 0);
// 测试视锥与AABB的碰撞
extern FAPI bool FHitFrustum_aabb(FFRUSTUM* f, FAABB* aabb);
// 测试视锥与平面的碰撞
// .p 平面上一点
// .n 平面法线
extern FAPI EF_INTERSECTION_TYPE FHitFrustum_plane(FFRUSTUM* f, FPLANE* plane);
extern FAPI EF_INTERSECTION_TYPE FHitFrustum_plane2(FFRUSTUM* f, FVECTOR3* p, FVECTOR3* n);


//----------------------------------------------------------------
//
//----------------------------------------------------------------
#include "Core/FBsc_Math_inl.h"

typedef FVector< FFLOAT16 >         FV_FFLOAT16;
typedef FVector< FVECTOR2 >         FV_VECTOR2;
typedef FVector< FVECTOR3 >         FV_VECTOR3;
typedef FVector< FVECTOR4 >         FV_VECTOR4;
typedef FVector< FMATRIX >          FV_MATRIX;
typedef FVector< FQUATERNION >      FV_QUATERNION;
typedef FVector< FCOLOR >           FV_COLOR;
typedef FVector< FTRIANGLE >        FV_TRIANGLE;
typedef FVector< FTRIANGLE_NORMAL > FV_TRIANGLE_NORMAL;
typedef FVector< FSPHERE >          FV_SPHERE;
typedef FVector< FRAY >             FV_RAY;
typedef FVector< FAABB >            FV_AABB;
typedef FVector< FAABB_CENTER >     FV_AABB_CENTER;
typedef FVector< FPLANE >           FV_PLANE;
typedef FVector< FFRUSTUM >         FV_FRUSTUM;
typedef FVector< FHITRESULT >       FV_HITRESULT;